<?php
namespace Modules\Ddtalk\Lib;

use S\Cache;

/**
 * access_token是公众号的全局唯一票据，公众号调用各接口时都需使用access_token。
 * 正常情况下access_token有效期为7200秒，重复获取将导致上次获取的access_token失效。
 * 由于获取access_token的api调用次数非常有限，建议开发者全局存储与更新access_token，频繁刷新access_token会导致api调用受限，影响自身业务。
 *
 * access_token 至少保留512B
 */
class AccessToken {
	const API_TOKEN_PATH            = '/gettoken';

	const ACCESS_TOKEN_CACHE_KEY    = '__THIS_IS_DDTALK_ACCESS_TOKEN__';

	/**
	 * @var array(
	 *      token
	 *      expire
	 * )
	 */
	private static $token   = array();

	private static $db      = null;

	/**
	 * 失效时间点
	 * @var int
	 */
	private static $expireat = 0;

	/**
	 * 从存储中获取access token
	 */
	public static function get($all=false, $reset=false) {
		//已经有且没有过期直接返回
		if(self::$token && (time() - self::$expireat < 0) && $reset == false ){
			return $all ? self::$token : self::$token['token'];
		}

		$token = self::store()->get(self::ACCESS_TOKEN_CACHE_KEY);
		if (empty($token)) {
			throw new Exception("获取access_token异常", 30001);
		}

		self::$token = json_decode($token, true);
		self::$expireat = time() + 300;

		return $all ? self::$token : self::$token['token'];
	}

	/**
	 * 获取并存储access_token
	 * @link http://ddtalk.github.io/dingTalkDoc/?spm=a3140.7785475.0.0.Q5c5r7#建立连接
	 *
	 * @return string {"access_token":"ACCESS_TOKEN","expires_in":7200}
	 */
	public static function fetch() {
		$token = '';
		$appid = \S\Config::confSecurity('ddtalk.corpid');
		$appsecret = \S\Config::confSecurity('ddtalk.corpsecret');

		for ($i=0; $i<3; $i++) {
			$token = Util::request(self::API_TOKEN_PATH.'?corpid='.$appid.'&corpsecret='.$appsecret, array(), false);
			if ($token) {
				// 记录下来供本次请求使用
				self::$token = array(
					'token'     => $token['access_token'],
					'expire'    => time() - 15 + $token['expires_in']
				);
				break;
			}
		}
		return $token;
	}

	/**
	 * 将从微信接口获取到的 token 写入存储
	 * @param $token
	 * @return mixed
	 */
	public static function set(array $token) {
		$ntoken = array(
			'token'     => $token['access_token'],
			'expire'    => time() - 15 + $token['expires_in']
		);

		$result = self::store()->set(self::ACCESS_TOKEN_CACHE_KEY, json_encode($ntoken), 7200);

		return $result ? $token : $result;
	}

	/**
	 * 获取存储
	 * @return \S\Cache\Abstraction
	 */
	protected static function store() {
		if(!self::$db){
			self::$db = Cache::pool('redis', 'common');
		}
		return self::$db;
	}

}